﻿using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Data;
using Nop.Core.Domain.Security;
using Nop.Core.Domain.Stores;
using Nop.Plugin.Widgets.AllInOne.Domain;
using Nop.Services.Events;
using Nop.Services.Security;
using Nop.Services.Stores;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Nop.Plugin.Widgets.AllInOne.Services
{
    /// <summary>
    /// Extended Customer service
    /// </summary>
    public partial class AllInOneService : IAllInOneService
    {
        #region Constants
        /// <summary>
        /// Key for caching
        /// </summary>
        /// <remarks>
        /// {0} : page ID
        /// </remarks>
        private const string ALLINONES_BY_ID_KEY = "Nop.allinone.id-{0}";
        /// <summary>
        /// Key pattern to clear cache
        /// </summary>
        private const string ALLINONES_PATTERN_KEY = "Nop.allinone.";

        #endregion

        #region Fields
        private readonly IRepository<AllInOneObject> _allInOneRepository;
        private readonly IRepository<AclRecord> _aclRepository;
        private readonly IRepository<StoreMapping> _storeMappingRepository;
        private readonly IWorkContext _workContext;
        private readonly IStoreContext _storeContext;
        private readonly IEventPublisher _eventPublisher;
        private readonly ICacheManager _cacheManager;
        private readonly IStoreMappingService _storeMappingService;
        private readonly IAclService _aclService;

        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="cacheManager">Cache manager</param>
        /// <param name="AllInOneRepository">AllInOne repository</param>
        /// <param name="aclRepository">ACL record repository</param>
        /// <param name="storeMappingRepository">Store mapping repository</param>
        /// <param name="workContext">Work context</param>
        /// <param name="storeContext">Store context</param>
        /// <param name="eventPublisher">Event publisher</param>
        /// <param name="storeMappingService">Store mapping service</param>
        /// <param name="aclService">ACL service</param>
        public AllInOneService(ICacheManager cacheManager,
            IRepository<AllInOneObject> allInOneRepository,
            IRepository<AclRecord> aclRepository,
            IRepository<StoreMapping> storeMappingRepository,
            IWorkContext workContext,
            IStoreContext storeContext,
            IEventPublisher eventPublisher,
            IStoreMappingService storeMappingService,
            IAclService aclService)
        {
            this._cacheManager = cacheManager;
            this._allInOneRepository = allInOneRepository;
            this._aclRepository = aclRepository;
            this._storeMappingRepository = storeMappingRepository;
            this._workContext = workContext;
            this._storeContext = storeContext;
            this._eventPublisher = eventPublisher;
            this._storeMappingService = storeMappingService;
            this._aclService = aclService;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Delete AllInOne
        /// </summary>
        /// <param name="AllInOne">AllInOne</param>
        public virtual void DeleteAllInOne(AllInOneObject allInOne)
        {
            if (allInOne == null)
                throw new ArgumentNullException("allInOne");

            _allInOneRepository.Delete(allInOne);

            //event notification
            _eventPublisher.EntityDeleted(allInOne);
        }

        /// <summary>
        /// Gets AllInOnes widgetZones
        /// </summary>
        /// <returns>AllInOne</returns>
        public virtual IList<string> GetAllInOnesWidgetZones()
        {
            var widgetZones = _allInOneRepository.Table.Where(x => x.Published).Select(x => x.WidgetZone).Distinct().ToArray();
            return widgetZones;
        }

        /// <summary>
        /// Gets all AllInOnes
        /// </summary>
        /// <param name="name">name</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <returns>AllInOnes</returns>
        public virtual IPagedList<AllInOneObject> GetAllInOnes(string name = "", int pageIndex = 0, int pageSize = int.MaxValue)
        {
            var query = _allInOneRepository.Table;
            if (!String.IsNullOrWhiteSpace(name))
                query = query.Where(s => s.Name.Contains(name));
            query = query.OrderBy(s => s.DisplayOrder);

            var allInOnes = query.ToList();

            //paging
            return new PagedList<AllInOneObject>(allInOnes, pageIndex, pageSize);
        }

        /// <summary>
        /// Gets AllInOnes by widgetZones
        /// </summary>
        /// <param name="widgetZones">widgetZones</param>
        /// <returns>AllInOne</returns>
        public virtual IList<AllInOneObject> GetAllInOnesByWidgetZones(string widgetZones)
        {
            var query = _allInOneRepository.Table.Where(s => s.WidgetZone == widgetZones).OrderBy(s => s.DisplayOrder);
            return query.ToList();
        }

        /// <summary>
        /// Gets a AllInOne
        /// </summary>
        /// <param name="allInOneId">AllInOne identifier</param>
        /// <returns>AllInOne</returns>
        public virtual AllInOneObject GetAllInOneById(int allInOneId)
        {
            if (allInOneId == 0)
                return null;

            string key = string.Format(ALLINONES_BY_ID_KEY, allInOneId);
            return _cacheManager.Get(key, () => { return _allInOneRepository.GetById(allInOneId); });
        }

        /// <summary>
        /// Inserts a AllInOne
        /// </summary>
        /// <param name="v">AllInOne</param>
        public virtual void InsertAllInOne(AllInOneObject allInOne)
        {
            if (allInOne == null)
                throw new ArgumentNullException("allInOne");

            _allInOneRepository.Insert(allInOne);

            //event notification
            _eventPublisher.EntityInserted(allInOne);
        }

        /// <summary>
        /// Updates the AllInOne
        /// </summary>
        /// <param name="AllInOne">AllInOne</param>
        public virtual void UpdateAllInOne(AllInOneObject allInOne)
        {
            if (allInOne == null)
                throw new ArgumentNullException("allInOne");

            _allInOneRepository.Update(allInOne);

            //event notification
            _eventPublisher.EntityUpdated(allInOne);
        }

        #endregion
    }
}
